package me.predatorray.xcollection;

import java.util.*;

public class DefaultXCollection<E> extends CollectionDelegate<E>
        implements XCollection<E> {

    public DefaultXCollection(Collection<E> delegated) {
        super(delegated);
    }

    @Override
    public <T> XCollection<T> map(Mapper<E, T> mapper) {
        Check.isNotNull(mapper);
        ArrayList<T> mapResult = new ArrayList<T>(size());
        for (E e : this) {
            mapResult.add(mapper.map(e));
        }
        return new DefaultXCollection<T>(Collections.unmodifiableCollection(
                mapResult));
    }

    @Override
    public E reduce(Reducer<E> reducer) {
        return reduceLeft(reducer);
    }

    @Override
    public E reduceLeft(Reducer<E> reducer) {
        Iterator<E> iterator = iterator();
        boolean firstTime = true;
        E reduceResult = null;
        while (iterator.hasNext()) {
            if (firstTime) {
                firstTime = false;
                reduceResult = iterator.next();
            } else {
                reduceResult = reducer.reduce(reduceResult, iterator.next());
            }
        }
        return reduceResult;
    }

    @Override
    public E reduceRight(Reducer<E> reducer) {
        return null;
    }

    @Override
    public E foldLeft(E initVal, Reducer<E> reducer) {
        E reduceResult = initVal;
        for (E e : this) {
            reduceResult = reducer.reduce(reduceResult, e);
        }
        return reduceResult;
    }

    @Override
    public E foldRight(E initVal, Reducer<E> reducer) {
        return null;
    }

    @Override
    public XCollection<E> scan(E initVal, Reducer<E> reducer) {
        return scanLeft(initVal, reducer);
    }

    @Override
    public XCollection<E> scanLeft(E initVal, Reducer<E> reducer) {
        ArrayList<E> scanResult = new ArrayList<E>(size());
        E previous = initVal;
        for (E e : this) {
            E per = reducer.reduce(previous, e);
            previous = per;
            scanResult.add(per);
        }
        return new DefaultXCollection<E>(Collections.unmodifiableCollection(
                scanResult));
    }

    @Override
    public XCollection<E> scanRight(E initVal, Reducer<E> reducer) {
        return null;
    }

    @Override
    public XCollection<E> filter(Filter<E> filter) {
        ArrayList<E> filterResult = new ArrayList<E>();
        for (E e : this) {
            if (filter.filter(e)) {
                filterResult.add(e);
            }
        }
        return new DefaultXCollection<E>(Collections.unmodifiableCollection(
                filterResult));
    }
}
